#ifndef __GEDIT_H__
#define __GEDIT_H__

/************************************************************************/
/* Graphic Form Editor                                                  */
/************************************************************************/
#define GFE_COPY                                      1000
#define GFE_CUT                                       1001
#define GFE_PASTE                                     1002
#define GFE_CLEARALL                                  1003
#define GFE_SELECTALL                                 1004
#define GFE_REDO                                      1005
#define GFE_UNDO                                      1006

#include "GView.h"

class Graphics;
class Document;
class GFont;

class TextRange
{
	int start, end;
public:
	TextRange(int pos = 0) { set(pos); }

    int                     startPos()const { return start;}
    int                     endPos()const { return end;}
	void                    setStart(int s) { start = s;}
	void                    setEnd(int e) { end = e; }
	void                    set(int pos = 0) { start = end = pos; }
	bool                    isEmpty()const { return (start == end); }
    bool                    contains(int pos) const { 
        if (isEmpty()) return false; 
        if (start < end) return (pos >= start && pos < end); 
        else return (pos >= end && pos < start);}
};

enum    SearchFlag { WholeWord = 0x01, MatchCase = 0x02, RegExp = 0x04, InHiddenText = 0x08};

class GEdit : protected GView
{
public:
	GEdit(GForm *parent = 0);
	virtual ~GEdit(void);

	int                      lineHeight()const { return GView::getVertThumb(); }
    void                     setLineHeight(int height) { GView::setThumb(VSCROLL, height);  }
    int                      charWidth() const { return GView::getHorzThumb();}
    void                     setCharWidth(int width) { GView::setThumb(HSCROLL, width); }
	int                      topLine()const { return m_topLine; }
	int                      bottomLine()const ;
    inline int               totalLines() const ;
    int                      totalVisualLines()const {return totalLines();} // some lines may be hidden
	void                     gotoLine(int docLine);// if the line was hidden ,it should be expand first
    GSize                    getClientSize()const { return GView::getClientSize(); }
    GRect                    textArea()const;
    GRect                    marginsArea() const;
    int                      getMargin(int type, long param = 0) const;
    enum                     MarginType { LineNumber = 0, Margin, BookMark, Folder};
    GSize                    stringSize(const GFont& font, const char* str, int len) const;
    GSize                    stringSize(const GFont& font, const GString& str) const;

    
//document
	int                      documentPos(const GPoint& point)const; //return doc pos as long as point in screen
    int                      documentLine(const GPoint& point) const; //some lines would be hidden   Document::LineFromPosition
    //map doc pos to screen point
	GPoint                   screenPoint(int docPos)const /*some lines were hidder*/;
    //map doc pos to screen line
    int                      screenLine(int docLine)const;
    //map doc line to screen line
	GRect                    getLineStringRect(int docLine)const { if (docLine < 0 || docLine > totalLines()-1) return GRect();}
    inline bool              isVisible(int docline) const ;
    int                      visualDocline(int docline, int offset = 1) const;
//caret
	int                      caretDocLine()const { return 0;}  // pDoc->getLine(m_ptCaretDocPos);
//	int                      caretScreenLine()const { return GView::getScreenRow(caretPoint());}
	int                      caretDocPos()const { return m_ptCaretDocPos;}  //docPos of caret
//	GPoint                   caretPoint() const { return screenPoint(m_ptCaretDocPos);}
	enum                     CaretMovement{ UP = 0, DOWN, LEFT, RIGHT};
	void                     moveCaret(CaretMovement m);
	void                     setCaretAt(int docPos);
	void                     setCaret(const GPoint& point) { setCaretAt(documentPos(point)); }

//selection
    bool                     inSelection(int docPos) const;
    bool                     inSelection(const GPoint& point)const { return inSelection(documentPos(point)); }  
    void                     setSelection(int startDocPos, int endDocPos){ m_selection.setStart(startDocPos); m_selection.setEnd(endDocPos);}
    void                     selectLines(int startLine, int endLine);
    void                     selectWord(int docPos);
protected:
	void                     _drawCaret(Graphics* pGraph);
    virtual void             _drawSelection(Graphics* pGraph) const;
    virtual void             _drawLine(Graphics* pGraph, int docLine, int scrRow) const;
    void                     _drawMargin(Graphics* pGraph) const;
    GCaret*                  m_pCaret; 
	int                      m_ptCaretDocPos;
    int                      m_topLine;
    enum                     SelectionType { Char, Word, Line };
    SelectionType            m_selType;
    enum                     DrapDrop{  None, Begin, Draging};
    DrapDrop                 m_drapState;
//     int                      m_DrapDocPos;
//     int                      m_DropDocPos;
    TextRange                m_selection;
    Document*                m_pDoc;
    Graphics*                m_pGraphics;

protected:
	virtual void             mousePressEvent( GMouseEvent& event );
	virtual void             mouseMoveEvent( GMouseEvent& event );
	virtual void             mouseReleaseEvent( GMouseEvent& event );
	virtual void             mouseDoubleClickEvent( GMouseEvent& event );
    virtual void             wheelEvent( GWheelEvent& event );
	virtual void             enterEvent( GMouseEvent& event ){ setCursor(GCursor::Text); }
	virtual void             leaveEvent( GMouseEvent& event ){ setCursor(GCursor::Arrow); }
    virtual void             itemEvent(int itemID, long param);
    virtual void             charPressEvent(wchar_t ch, void* param = 0);
    virtual void             dropEvent(const GDropEvent& event);
    virtual void             paintEvent( GPaintEvent& event );
    virtual void             scrollEvent( GScrollEvent& event );
	
public:
	virtual void             copy(){}
	virtual void             cut(){}
	virtual void             paste(){}
	virtual void             clearAll(){}
	virtual void             selectAll();
	virtual void             undo(){}
	virtual void             redo(){}

	void                     newLine();
	void                     indent(bool forwards = true){}
	void                     findText(char* text, int len , SearchFlag flag){}
    void                     zoom(int  z);
    bool                     insertString(int docPos, const char* pstr, int len);
    bool                     deleteString(int docPos, int len);
	
private:
    // properties
    uint                     inOverstrike                 : 1;
    uint                     isCaretSticky                : 1;
    uint                     isEndAtLastLine              : 1;
    uint                     margin_LineNumber            : 1;
    uint                     margin_BookMark              : 1;
    uint                     margin_Fold                  : 1;
//    uint                     tab_on                       : 1;
//    uint                     tab_size                     : 4;
};

#endif 